package br.pucrio.inf.tamdera.prolog;

import java.util.ArrayList;
import java.util.List;

import jpl.Query;
import br.pucrio.inf.tamdera.Constants;
import br.pucrio.inf.tamdera.QueryReportBean;
import br.pucrio.inf.tamdera.prolog.qbeans.PrologQueryBean;
import br.pucrio.inf.tamdera.prolog.utils.PrologIntegrationConstants;
import br.pucrio.inf.tamdera.utils.ConverterPrologTamderaUtils;
import br.pucrio.inf.tamdera.utils.Pair;

public class PrologInterface {

	public static final String consultTemplate = PrologIntegrationConstants.TEMPLATE_CONSULT;

	public static final String resultSource = Constants.RESULT_QUERY_SOURCE;

	public static final String resultTarget = Constants.RESULT_QUERY_TARGET;

	/**
	 * 
	 * @param queryBean
	 * @param projectPrologFilePath
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static QueryReportBean executeQuery(PrologQueryBean queryBean, String projectPrologFilePath) 
	{

		importingPrologFiles( projectPrologFilePath );

		Query prologquery = new Query( queryBean.getQuery() );
		System.out.println( queryBean.getQuery()  + "  " + (prologquery.hasSolution() ? "succeeded" : "failed") );

		String ruleDecl = queryBean.getDeclString();
		QueryReportBean report = new QueryReportBean( ruleDecl );
		report.setSuccessfullyChecked( true );

		List<String> violationsMessages = new ArrayList<String>();
		while ( prologquery.hasMoreSolutions() )
		{
			report.setSuccessfullyChecked( false );
			java.util.Hashtable violations = prologquery.nextSolution();

			String text = "Violation: ";

			for ( Object parameter : violations.keySet() )
			{
				String paramKey = (String)parameter;
				Object result = violations.get(paramKey);
				text += paramKey + " -> "  + result;
				text += ";";
			}

			violationsMessages.add( text );
		}
		report.setViolations( violationsMessages );

		return report;
	}


	private static void importingPrologFiles ( String projectPrologFilePath )
	{

		String importProjectRepresentation =  String.format( consultTemplate, projectPrologFilePath);
		Query q1 = new Query( importProjectRepresentation );
		System.out.println( importProjectRepresentation + " " +  (q1.hasSolution() ? "succeeded" : "failed") );

		String mappingPl = PrologIntegrationConstants.mappingPrologFile;
		String importMapping =  String.format( consultTemplate, mappingPl);
		Query q2 = new Query( importMapping );
		System.out.println(  importMapping + " " + (q2.hasSolution() ? "succeeded" : "failed") );

		String propertyMappingPl = PrologIntegrationConstants.propertyMappingPrologFile;
		String importPropertyMapping =  String.format( consultTemplate, propertyMappingPl);
		Query q6 = new Query( importPropertyMapping );
		System.out.println(  importPropertyMapping + " " + (q6.hasSolution() ? "succeeded" : "failed") );


		String dependenciesPl = String.format( consultTemplate, PrologIntegrationConstants.dependencyRelationsFile);
		Query q3 = new Query( dependenciesPl );
		System.out.println(  dependenciesPl + " " + (q3.hasSolution() ? "succeeded" : "failed") );

		String driftRelationsPl =  String.format( consultTemplate, PrologIntegrationConstants.driftRelationsFile);
		Query q4 = new Query( driftRelationsPl );
		System.out.println(  driftRelationsPl + " " + (q4.hasSolution() ? "succeeded" : "failed") );


		String utils =  String.format( consultTemplate, PrologIntegrationConstants.utilsFile);
		Query q5 = new Query( utils );
		System.out.println(  utils + " " + (q5.hasSolution() ? "succeeded" : "failed") );

		String importAntiErosionFacts =  String.format( consultTemplate, PrologIntegrationConstants.antiErosionDesignRulePrologFile );
		Query q8 = new Query( importAntiErosionFacts );
		System.out.println(  importAntiErosionFacts + " " + (q8.hasSolution() ? "succeeded" : "failed") );
		
		String importErosionConsistencyChecker =  String.format( consultTemplate, PrologIntegrationConstants.antiErosionConsistencyCheckerFile );
		Query q7 = new Query( importErosionConsistencyChecker );
		System.out.println(  importErosionConsistencyChecker + " " + (q7.hasSolution() ? "succeeded" : "failed") );

	}


	/**
	 * 
	 * @param parents
	 * @param projectPrologFilePath 
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static List<String> getSubClassesOfClasses (List<String> parents, String projectPrologFilePath)
	{
		List<String> subClasses = new ArrayList<String>();

		//importing prolog facts

		importingPrologFiles( projectPrologFilePath );

		for ( String parent : parents )
		{


			Pair<String, String> pair = ConverterPrologTamderaUtils.getPrologClassNameFromTamderaClassName( parent );

			String classNameStr = pair.getSecond();
			String packageStr =  pair.getFirst();


			String classPrologFact = String.format( PrologIntegrationConstants.CLASS_TEMPLATE_FACT, packageStr, classNameStr );

			String inheritsConsult = String.format( PrologIntegrationConstants.INHERITS_QUERY_TEMPLATE, 
					Constants.RESULT_QUERY_SUBCLASS, classPrologFact);

			Query prologquery = new Query( inheritsConsult );
			System.out.println( inheritsConsult  + "  " + (prologquery.hasSolution() ? "succeeded" : "failed") );

			while ( prologquery.hasMoreSolutions() )
			{
				java.util.Hashtable solutions = prologquery.nextSolution();
				final String subclassInProlog =  solutions.get( Constants.RESULT_QUERY_SUBCLASS ).toString();

				subClasses.add( subclassInProlog );
			}
		}

		return subClasses;
	}


	@SuppressWarnings("rawtypes")
	public static List<String> extractAllClassesFromPrologProjectFile( final String projectPrologFilePath ) 
	{
		List<String> result = new ArrayList<String>();

		//importing prolog facts

		importingPrologFiles( projectPrologFilePath );

		final String allClassesQuery = String.format(PrologIntegrationConstants.ALLCLASSES_QUERY_TEMPLATE, 
				Constants.RESULT_QUERY_PACKAGE, Constants.RESULT_QUERY_CLASSNAME );

		Query prologquery = new Query( allClassesQuery );
		System.out.println( allClassesQuery  + "  " + (prologquery.hasSolution() ? "succeeded" : "failed") );

		while ( prologquery.hasMoreSolutions() )
		{
			java.util.Hashtable solutions = prologquery.nextSolution();

			final String packageName =  solutions.get( Constants.RESULT_QUERY_PACKAGE ).toString();
			final String className =  solutions.get( Constants.RESULT_QUERY_CLASSNAME ).toString();

			final String prologClassName = packageName + PrologIntegrationConstants.PACKAGE_SEPARATOR_IN_PROLOG
					+ className; 

			result.add( prologClassName );
		}


		return result;
	}

}
